#include <iostream>
#include <vector>
#include <fstream>
#include <limits>
#include <cmath>
#include <algorithm>
#include <iterator>

#include "gmp.h"

std::ifstream in ("in.txt");
std::ofstream out ("out.txt");

const double eps = 4 * std::numeric_limits<double>::epsilon();

struct point
{
	double x,y;
	bool operator < (const point& p) const
	{
		return (x < p.x) || ((x == p.x) && (y < p.y));
	}
};


void input(std::vector<point> &points)
{
	int n;
	std::cin >> n;
	for (int i = 0; i < n; i++)
	{
		point a;
		std::cin >> a.x >> a.y;
		points.push_back(a);
	}
}

bool equal(const point &a,const point &b)
{
	return (a.x == b.x) && (a.y == b.y);
}

int  left_turn_add_precision(const point &a, const point &b, const point &c)
{
	mpq_t ax, ay, bx, by, cx, cy;
	mpq_init(ax);
	mpq_init(ay);
	mpq_init(bx);
	mpq_init(by);
	mpq_init(cx);
	mpq_init(cy);
	mpq_set_d(ax, a.x);
	mpq_set_d(ay, a.y);
	mpq_set_d(bx, b.x);
	mpq_set_d(by, b.y);
	mpq_set_d(cx, c.x);
	mpq_set_d(cy, c.y);
	mpq_t tmp1, tmp2, tmp3, mul1 ,mul2;
	mpq_init(tmp1);
	mpq_init(tmp2);
	mpq_init(tmp3);
	mpq_init(mul1);
	mpq_init(mul2);
	mpq_sub(tmp1, bx, ax);				//tmp1 = b.x - a.x
	mpq_sub(tmp2, cy, ay);				//tmp2 = c.y - a.y
	mpq_mul(mul1, tmp1, tmp2);			//mul1 = (b.x - a.x) * (c.y - a.y)
	mpq_sub(tmp1, by, ay);				//tmp2 = b.y - a.y
	mpq_sub(tmp2, cx, ax);				//tmp3 = c.x - a.x
	mpq_mul(mul2, tmp1, tmp2);			//mul2 = (b.y - a.y) * (c.x - a.x)	
	mpq_sub(tmp3, mul1, mul2);			//tmp3 = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
	mpq_clear(tmp1);
	mpq_clear(tmp2);
	mpq_clear(mul1);
	mpq_clear(mul2);
	int ret = mpq_sgn(tmp3);
	mpq_clear(tmp3);
	return ret;
}

int left_turn(const point &a, const point &b, const point &c)
{
	double ans = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
	if  (eps * (std::abs((b.x - a.x) * (c.y - a.y)) + std::abs((b.y - a.y) * (c.x - a.x))) < ans)
	{
		return 1;
	}
	if  (-(eps * (std::abs((b.x - a.x) * (c.y - a.y)) + std::abs((b.y - a.y) * (c.x - a.x)))) > ans)
	{
		return -1;
	}
	return left_turn_add_precision(a,b,c);
}

int compare_distantions_add_precision(const point &a, const point &b, const point &c, const point &d)
{
	mpq_t ax, ay, bx, by, cx, cy, dx, dy;
	mpq_init(ax);
	mpq_init(ay);
	mpq_init(bx);
	mpq_init(by);
	mpq_init(cx);
	mpq_init(cy);
	mpq_init(dx);
	mpq_init(dy);
	mpq_set_d(ax, a.x);
	mpq_set_d(ay, a.y);
	mpq_set_d(bx, b.x);
	mpq_set_d(by, b.y);
	mpq_set_d(cx, c.x);
	mpq_set_d(cy, c.y);
	mpq_set_d(dx, d.x);
	mpq_set_d(dy, d.y);
	mpq_t tmp1, tmp2, tmp3, mul1, mul2;
	mpq_init(tmp1);
	mpq_init(tmp2);
	mpq_init(tmp3);
	mpq_init(mul1);
	mpq_init(mul2);
	mpq_sub(tmp1, bx, ax);				//tmp1 = b.x - a.x
	mpq_sub(tmp2, cy, dy);				//tmp2 = c.y - d.y
	mpq_mul(mul1, tmp1, tmp2);			//mul1 = (b.x - a.x) * (c.y - d.y)
	mpq_sub(tmp1, by, ay);				//tmp1 = b.y - a.y
	mpq_sub(tmp2, cx, dx);				//tmp2 = c.x - d.x
	mpq_mul(mul2, tmp1, tmp2);			//mul2 = (b.y - a.y) * (c.x - d.x)
	mpq_sub(tmp3, mul1, mul2);			//tmp3 = (b.x - a.x) * (c.y - d.y) - (b.y - a.y) * (c.x - d.x)
	mpq_clear(tmp1);
	mpq_clear(tmp2);
	mpq_clear(mul1);
	mpq_clear(mul2);
	int ret = mpq_sgn(tmp3);
	mpq_clear(tmp3);
	return ret;
}

int compare_distantions(const point &a, const point &b, const point &c, const point &d)
{
	double ans = (b.x - a.x) * (c.y - d.y) - (b.y - a.y) * (c.x - d.x);
	if (eps * (std::abs((b.x - a.x) * (c.y - d.y)) + std::abs((b.y - a.y) * (c.x - d.x))) < ans)
	{
		return 1;
	}
	if (-(eps * (std::abs((b.x - a.x) * (c.y - d.y)) + std::abs((b.y - a.y) * (c.x - d.x)))) > ans)
	{
		return -1;
	}
	return compare_distantions_add_precision(a,b,c,d);
}

template <class Iter>
void q_hull(std::vector<point> &convex_hull, const point& left, const point& right, Iter& begin, Iter& end)	
{
	if (begin == end)
	{
		return;
	}
	point top;
	auto top_ind = std::min_element(begin,end,[left,right] (const point &a, const point &b)
	{
		return (!equal(a,left) && !equal(a,right) && (compare_distantions(left, right, a, b) == 1));
	});
	top = (*top_ind);
	Iter S1_L = std::stable_partition(begin,end,[left,top] (point &d)
	{
		return (left_turn(left,top,d) == 1);
	});	
	Iter S1_R = std::stable_partition(S1_L, end, [top,right] (point &d)
	{
		return (left_turn(top,right,d) == 1);
	});
	q_hull(convex_hull, left, top, begin, S1_L);
	convex_hull.push_back(top);	
	q_hull(convex_hull, top, right, S1_L, S1_R);
}

void q_hull_start(std::vector<point> &points, std::vector<point> &convex_hull)
{
	point left, right;
	auto minmax = std::minmax_element(points.begin(),points.end());
	left = *(minmax.first);
	right = *(minmax.second);
	std::vector <point>::iterator S1 = std::stable_partition(points.begin(),points.end(),[left,right] (point &d)
	{
		return (left_turn(left,right,d) == 1);
	});
	std::vector <point>::iterator S2 = std::stable_partition(S1,points.end(),[left,right] (point &d)
	{
		return (left_turn(left,right,d) == -1);
	});
	q_hull(convex_hull, right, left, S1, S2);
	convex_hull.push_back(left);
	q_hull(convex_hull, left, right, points.begin(), S1);
	convex_hull.push_back(right);
}

int main()
{
	std::vector<point> answer;
	std::vector<point> points;
	input(points);
	if (points.size() == 1)
	{
		std::cout << 1 << '\n';
		std::cout.precision(42);
		std::cout << points[0].x << ' ' << points[0].y;
	}
	else
	{
		q_hull_start(points,answer);
		if (equal(answer[0],answer[1]))
		{
			answer.pop_back();
		}
		std::cout << answer.size() << '\n';
		std::cout.precision(42);
		for (size_t i = answer.size() - 1; i < answer.size() ; i--)
		{
			std::cout << answer[i].x << ' ' << answer[i].y << '\n';
		}
	}
	return 0;
}
